package character

import (
	"bytes"
	"compress/gzip"
	"crypto/rand"
	"encoding/base64"
	"golang.org/x/crypto/bcrypt"
	"io"
	"math/big"
	"strconv"
	"time"
	"unicode"
)

var randomArr = []string{"2", "3", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}
var yearArr = []string{"A", "B", "C", "D", "F", "G", "H", "I", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}
var mothArr = []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C"}

func Hash(str string) (string, error) {
	hashed, err := bcrypt.GenerateFromPassword([]byte(str), bcrypt.DefaultCost)
	return string(hashed), err
}

func CheckHash(password, hashedPassword string) error {
	// 将哈希字符串转换为字节切片
	hash := []byte(hashedPassword)
	// 使用 bcrypt.CompareHashAndPassword 验证密码
	err := bcrypt.CompareHashAndPassword(hash, []byte(password))
	return err
}

// ContainsChinese 判断字符串中是否含有中文字符
func ContainsChinese(str string) bool {
	for _, r := range str {
		if unicode.Is(unicode.Scripts["Han"], r) {
			return true
		}
	}
	return false
}

func Pkcs5Padding(src []byte, blockSize int) []byte {
	padding := blockSize - (len(src) % blockSize)
	padText := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(src, padText...)
}

func Pkcs5Unpacking(src []byte) []byte {
	length := len(src)
	unpacking := int(src[length-1])
	return src[:(length - unpacking)]
}

func CompressAndBase64Encode(params []byte) (string, error) {
	var buf bytes.Buffer
	// 创建gzip writer
	gzipWriter := gzip.NewWriter(&buf)
	// 写入params数据
	if _, err := gzipWriter.Write(params); err != nil {
		return "", err
	}
	// 关闭gzip writer，这一步很重要，它会在数据末尾添加结束标记
	if err := gzipWriter.Close(); err != nil {
		return "", err
	}
	// 对压缩后的数据进行Base64编码
	return base64.StdEncoding.EncodeToString(buf.Bytes()), nil
}

func DeCompressAndBase64Decode(encodedParams string) ([]byte, error) {
	decodedParams, err := base64.StdEncoding.DecodeString(encodedParams)
	if err != nil {
		return nil, err
	}
	var buf bytes.Buffer
	buf.Write(decodedParams)
	// 创建gzip reader
	gzipReader, err := gzip.NewReader(&buf)
	if err != nil {
		return nil, err
	}
	defer func() {
		_ = gzipReader.Close()
	}()
	// 读取解压后的数据
	uncompressedParams, err := io.ReadAll(gzipReader)
	if err != nil {
		return nil, err
	}
	return uncompressedParams, nil
}

// GzipEncode GZip压缩
func GzipEncode(params string) ([]byte, error) {
	var b bytes.Buffer
	gz := gzip.NewWriter(&b)
	if _, err := gz.Write([]byte(params)); err != nil {
		return nil, err
	}
	if err := gz.Flush(); err != nil {
		return nil, err
	}
	if err := gz.Close(); err != nil {
		return nil, err
	}
	return b.Bytes(), nil
}

// GzipDecode 解压缩
func GzipDecode(encodedParams string) ([]byte, error) {
	var buf bytes.Buffer
	buf.Write([]byte(encodedParams))
	// 创建gzip reader
	gzipReader, err := gzip.NewReader(&buf)
	if err != nil {
		return nil, err
	}
	defer gzipReader.Close()
	// 读取解压后的数据
	uncompressedParams, err := io.ReadAll(gzipReader)
	if err != nil {
		panic(err)
	}
	return uncompressedParams, nil
}

// GenerateBookingId 生成订单号
func GenerateBookingId(orderIdType string, orderType string) (orderId string) {
	nowTime := time.Now()
	orderId += orderIdType
	orderId += orderType
	orderId += yearArr[(nowTime.Year() - 2016)]
	orderId += mothArr[(nowTime.Month() - 1)]
	orderId += strconv.Itoa(nowTime.Day())
	randCount := len(randomArr)
	test := int64(randCount)
	for i := 0; i < 4; i++ {
		randKeyInt64, err := rand.Int(rand.Reader, big.NewInt(test))
		if err != nil {
			panic(err)
		}
		randKey := (int)(randKeyInt64.Int64())
		orderId += randomArr[randKey]
	}
	return
}

func GetPassengerName(surname, givenNames string) string {
	if ContainsChinese(givenNames) || surname == "" {
		return surname + givenNames
	}
	return surname + "/" + givenNames
}

func GetPolicyNo(prefix string) (policyNo string) {
	now := time.Now()
	policyNo = prefix + strconv.FormatInt(int64(now.Year()), 10)[2:] + strconv.FormatInt(int64(now.Month()), 10) + strconv.FormatInt(int64(now.Day()), 10) + strconv.FormatInt(now.UnixMicro(), 10)[10:]
	return
}
